package com.jsptags.navigation.pager;

import com.jsptags.navigation.pager.parser.PagerTagExport;
import com.jsptags.navigation.pager.parser.ParseException;
import com.jsptags.navigation.pager.parser.TagExportParser;
import java.net.URLEncoder;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.jsp.*;
import javax.servlet.jsp.tagext.TagSupport;

@SuppressWarnings("serial")
public final class PagerTag extends TagSupport {

	//标签名
	static final String DEFAULT_ID = "pager";
	private static final int DEFAULT_MAX_ITEMS = 0x7fffffff;
	private static final int DEFAULT_MAX_PAGE_ITEMS = 10;
	private static final int DEFAULT_MAX_INDEX_PAGES = 10;
	static final String OFFSET_PARAM = ".offset";
	static final String PAGE = "page";
	static final String REQUEST = "request";
	static final String CENTER = "center";
	static final String FORWARD = "forward";
	static final String HALF_FULL = "half-full";
	//请求地址
	private String url;
	private String index;
	private int items;
	private int maxItems;
	private int maxPageItems;
	private int maxIndexPages;
	private boolean isOffset;
	private String export;
	private String scope;
	private StringBuffer uri;
	private int params;
	private int offset;
	private int itemCount;
	private int pageNumber;
	private Integer pageNumberInteger;
	private String idOffsetParam;
	private PagerTagExport pagerTagExport;
	private Object oldPager;
	private Object oldOffset;
	private Object oldPageNumber;

	public final void setId(String s) {
		super.setId(s);
		idOffsetParam = s + ".offset";
	}

	public final void setUrl(String s) {
		url = s;
	}

	public final String getUrl() {
		return url;
	}

	public final void setIndex(String s) throws JspException {
		if (s != null && !"center".equals(s) && !"forward".equals(s)
				&& !"half-full".equals(s)) {
			throw new JspTagException(
					"value for attribute \"index\" must be either \"center\", \"forward\" or \"half-full\".");
		} else {
			index = s;
			return;
		}
	}

	public final String getIndex() {
		return index;
	}

	public final void setItems(int i) {
		items = i;
	}

	public final int getItems() {
		return items;
	}

	public final void setMaxItems(int i) {
		maxItems = i;
	}

	public final int getMaxItems() {
		return maxItems;
	}

	public final void setMaxPageItems(int i) {
		maxPageItems = i;
	}

	public final int getMaxPageItems() {
		return maxPageItems;
	}

	public final void setMaxIndexPages(int i) {
		maxIndexPages = i;
	}

	public final int getMaxIndexPages() {
		return maxIndexPages;
	}

	public final void setIsOffset(boolean flag) {
		isOffset = flag;
	}

	public final boolean getIsOffset() {
		return isOffset;
	}

	public final void setExport(String s) throws JspException {
		if (export != s)
			try {
				pagerTagExport = TagExportParser.parsePagerTagExport(s);
			} catch (ParseException parseexception) {
				throw new JspTagException(parseexception.getMessage());
			}
		export = s;
	}

	public final String getExport() {
		return export;
	}

	public final void setScope(String s) throws JspException {
		if (s != null && !"page".equals(s) && !"request".equals(s)) {
			throw new JspTagException(
					"value for attribute \"scope\" must be either \"page\" or \"request\".");
		} else {
			scope = s;
			return;
		}
	}

	public final String getScope() {
		return scope;
	}

	final void addParam(String s, String s1) {
		if (s1 != null) {
			s = URLEncoder.encode(s);
			s1 = URLEncoder.encode(s1);
			uri.append(params != 0 ? '&' : '?').append(s).append('=')
					.append(s1);
			params++;
		} else {
			String as[] = pageContext.getRequest().getParameterValues(s);
			if (as != null) {
				s = URLEncoder.encode(s);
				int i = 0;
				for (int j = as.length; i < j; i++) {
					s1 = URLEncoder.encode(as[i]);
					uri.append(params != 0 ? '&' : '?').append(s).append('=')
							.append(s1);
					params++;
				}

			}
		}
	}

	final boolean nextItem() {
		boolean flag = false;
		if (itemCount < maxItems) {
			flag = itemCount >= offset && itemCount < offset + maxPageItems;
			itemCount++;
		}
		return flag;
	}

	final int getOffset() {
		return offset;
	}

	final boolean isIndexNeeded() {
		return offset != 0 || getItemCount() > maxPageItems;
	}

	final boolean hasPrevPage() {
		return offset > 0;
	}

	final boolean hasNextPage() {
		return getItemCount() > getNextOffset();
	}

	final boolean hasPage(int i) {
		return i >= 0 && getItemCount() > i * maxPageItems;
	}

	final int getPrevOffset() {
		return Math.max(0, offset - maxPageItems);
	}

	final int getNextOffset() {
		return offset + maxPageItems;
	}

	final String getOffsetUrl(int i) {
		int j = uri.length();
		uri.append(params != 0 ? '&' : '?').append(idOffsetParam).append('=')
				.append(i);
		String s = uri.toString();
		uri.setLength(j);
		return s;
	}

	final String getPageUrl(int i) {
		return getOffsetUrl(maxPageItems * i);
	}

	final Integer getOffsetPageNumber(int i) {
		return new Integer(1 + pageNumber(i));
	}

	final Integer getPageNumber(int i) {
		if (i == pageNumber)
			return pageNumberInteger;
		else
			return new Integer(1 + i);
	}

	final int getPageNumber() {
		return pageNumber;
	}

	final int getPageCount() {
		return pageNumber(getItemCount());
	}

	final int getFirstIndexPage() {
		int i = 0;
		int j = maxIndexPages / 2;
		if ("forward".equals(index))
			i = Math.min(pageNumber + 1, getPageCount());
		else if (!"half-full".equals(index) || pageNumber >= j) {
			int k = getPageCount();
			if (k > maxIndexPages) {
				i = Math.max(0, pageNumber - j);
				int l = k - i;
				if (l < maxIndexPages)
					i -= maxIndexPages - l;
			}
		}
		return i;
	}

	final int getLastIndexPage(int i) {
		int j = getPageCount();
		int k = maxIndexPages / 2;
		int l;
		if ("half-full".equals(index) && pageNumber < k)
			l = pageNumber + k;
		else
			l = i + maxIndexPages;
		return (j > l ? l : j) - 1;
	}

	final int getItemCount() {
		return items == 0 ? itemCount : items;
	}

	private final int pageNumber(int i) {
		return i / maxPageItems + (1 - (i % maxPageItems != 0 ? 0 : 1));
	}

	public final int doStartTag() throws JspException {
		String s;
		if (url != null) {
			s = url;
		} else {
			s = ((HttpServletRequest) pageContext.getRequest()).getRequestURI();
			int i = s.indexOf('?');
			if (i != -1)
				s = s.substring(0, i);
		}
		if (uri == null)
			uri = new StringBuffer(s.length() + 32);
		else
			uri.setLength(0);
		uri.append(s);
		params = 0;
		offset = 0;
		itemCount = 0;
		String s1 = pageContext.getRequest().getParameter(idOffsetParam);
		if (s1 != null)
			try {
				offset = Math.max(0, Integer.parseInt(s1));
				if (isOffset)
					itemCount = offset;
			} catch (NumberFormatException numberformatexception) {
			}
		pageNumber = pageNumber(offset);
		pageNumberInteger = new Integer(1 + pageNumber);
		if ("request".equals(scope)) {
			ServletRequest servletrequest = pageContext.getRequest();
			oldPager = servletrequest.getAttribute(id);
			servletrequest.setAttribute(id, this);
			if (pagerTagExport != null) {
				String s3;
				if ((s3 = pagerTagExport.getPageOffset()) != null) {
					oldOffset = servletrequest.getAttribute(s3);
					servletrequest.setAttribute(s3, new Integer(offset));
				}
				if ((s3 = pagerTagExport.getPageNumber()) != null) {
					oldPageNumber = servletrequest.getAttribute(s3);
					servletrequest.setAttribute(s3, pageNumberInteger);
				}
			}
		} else if (pagerTagExport != null) {
			String s2;
			if ((s2 = pagerTagExport.getPageOffset()) != null) {
				oldOffset = pageContext.getAttribute(s2);
				pageContext.setAttribute(s2, new Integer(offset));
			}
			if ((s2 = pagerTagExport.getPageNumber()) != null) {
				oldPageNumber = pageContext.getAttribute(s2);
				pageContext.setAttribute(s2, pageNumberInteger);
			}
		}
		return 1;
	}

	private static final void restoreAttribute(ServletRequest servletrequest,
			String s, Object obj) {
		if (obj != null)
			servletrequest.setAttribute(s, obj);
		else
			servletrequest.removeAttribute(s);
	}

	private static final void restoreAttribute(PageContext pagecontext,
			String s, Object obj) {
		if (obj != null)
			pagecontext.setAttribute(s, obj);
		else
			pagecontext.removeAttribute(s);
	}

	public final int doEndTag() throws JspException {
		if ("request".equals(scope)) {
			ServletRequest servletrequest = pageContext.getRequest();
			restoreAttribute(servletrequest, id, oldPager);
			oldPager = null;
			if (pagerTagExport != null) {
				String s1;
				if ((s1 = pagerTagExport.getPageOffset()) != null) {
					restoreAttribute(servletrequest, s1, oldOffset);
					oldOffset = null;
				}
				if ((s1 = pagerTagExport.getPageNumber()) != null) {
					restoreAttribute(servletrequest, s1, oldPageNumber);
					oldPageNumber = null;
				}
			}
		} else if (pagerTagExport != null) {
			String s;
			if ((s = pagerTagExport.getPageOffset()) != null) {
				restoreAttribute(pageContext, s, oldOffset);
				oldOffset = null;
			}
			if ((s = pagerTagExport.getPageNumber()) != null) {
				restoreAttribute(pageContext, s, oldPageNumber);
				oldPageNumber = null;
			}
		}
		if (uri.capacity() > 1024)
			uri = null;
		pageNumberInteger = null;
		return 6;
	}

	public final void release() {
		url = null;
		index = null;
		items = 0;
		maxItems = 0x7fffffff;
		maxPageItems = 10;
		maxIndexPages = 10;
		isOffset = false;
		export = null;
		scope = null;
		uri = null;
		params = 0;
		offset = 0;
		itemCount = 0;
		pageNumber = 0;
		pageNumberInteger = null;
		idOffsetParam = "pager.offset";
		pagerTagExport = null;
		oldPager = null;
		oldOffset = null;
		oldPageNumber = null;
		super.release();
	}

	public PagerTag() {
		url = null;
		index = null;
		items = 0;
		maxItems = 0x7fffffff;
		maxPageItems = 10;
		maxIndexPages = 10;
		isOffset = false;
		export = null;
		scope = null;
		uri = null;
		params = 0;
		offset = 0;
		itemCount = 0;
		pageNumber = 0;
		pageNumberInteger = null;
		idOffsetParam = "pager.offset";
		pagerTagExport = null;
		oldPager = null;
		oldOffset = null;
		oldPageNumber = null;
		id = "pager";
	}
}
